#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    this->setWindowTitle("SPY Client");

    this->ui->stackedWidget->setCurrentIndex(0); //set GUI page to login page
    this->resize(649, 327); //set size for non-admin user
    this->ui->stackedWidget->resize(651, 291);

    this->ui->Client_MessageDiplay->setColumnWidth(0, 100);
    this->ui->Client_MessageDiplay->setColumnWidth(1, 150);

    this->ui->Management_MessageDisplay->setColumnWidth(0, 100);
    this->ui->Management_MessageDisplay->setColumnWidth(1, 150);


    //ui->Welcome_IP->setInputMask("000.000.000.000");  //sets the line edit mask for IP address
    this->superadmin = false;

    secureSocket = new QSslSocket;

    connect(secureSocket, SIGNAL(readyRead()), this, SLOT(Receive_Message()));
    connect(secureSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(SSL_Error(QList<QSslError>)));

    ui->Status->setText("");

    this->ui->Welcome_Username->setFocus();
}

MainWindow::~MainWindow()
{
    delete ui;
}








//Network SLOTS
void MainWindow::Receive_Message()          //Slot for receiving information from the server
{
    qDebug() << "Received a message";

    this->setEnabled(true); //reenable the GUI - only applies for the sign in phase. as the client waits for authentication from the server, user input is disabled.

    QDataStream in(secureSocket);
    in.setVersion(QDataStream::Qt_4_0);

    if (blockSize == 0) {
        if (secureSocket->bytesAvailable() < (int)sizeof(quint16))
            return;
        in >> blockSize;
    }

    if (secureSocket->bytesAvailable() < blockSize)
        return;

    QString message;
    in >> message;      //read in the message from the server into the QString "message"


    qDebug() << "\tMessage sent to me: "+ message;


    //Begin parsing of the message
    QStringList data = message.split("::");
    if (message == "")
    {
        qDebug() << "\tNo data returned from the server";
        QMessageBox::warning(this, tr("Sign In Error"), tr("No data was returned from the server."),
                                                         QMessageBox::Ok | QMessageBox::Default);
        //secureSocket->abort();
        secureSocket->disconnectFromHost();
        ui->Status->setText("");
        return;
    }

    if (data.front() == "0")            //if this is true, the user failed to be authenticated
    {
        qDebug() << "\tUser not authenticated";
        QMessageBox::warning(this, tr("Invalid Sign In"), tr("Invalid username or password."),
                                                         QMessageBox::Ok | QMessageBox::Default);
        secureSocket->abort();
        ui->Status->setText("");
        return;
    }
    else if (data.front() == "1")       //if this is true, the user was authenticated successfully and is receiving data
    {
        qDebug() << "\tUser was authenticated...";

        messages.clear();
        usersList.clear();
        if (data.size() < 2)    //makes sure message wasn't corrupted
        {
            qDebug() << "data.size() IS NOT LESS THAN 2... RETURNING";
            return;
        }

        if (data.at(1) == "0")  //if this is true, the user is not a super admin and only receives messages as data
        {
            qDebug() << "\tNot Admin";
            this->setWindowTitle("SPY Client");
            if (data.size() != 3)
            {
                qDebug() << "data.size() DOES NOT EQUAL 3... RETURNING (NOT ADMIN)";
                return;
            }
            superadmin = false;
            QStringList m = data.at(2).split("&&");
            QStringList::iterator it;
            for (it = m.begin(); it < m.end(); it++)
            {
                QString cur = *it;
                QStringList mData = cur.split("__");

                if (mData.size() == 3)
                {
                    qDebug() << "\tAppending a message...";
                    messages.append(cur);
                }
            }
        }
        else if (data.at(1) == "1") //if this is true, the user is a super admin and receives all messages AND user info
        {
            qDebug() << "\tIs Admin";
            this->setWindowTitle("SPY Administrative Client");

            if (data.size() != 4)
            {
                qDebug() << "data.size() DOES NOT EQUAL 4... RETURNING (IS ADMIN)";
                return;
            }
            superadmin = true;
            QStringList m = data.at(2).split("&&"); //read the messages from the data
            QStringList::iterator it;
            for (it = m.begin(); it < m.end(); it++)
            {
                QString cur = *it;
                QStringList mData = cur.split("__");

                if (mData.size() == 3)
                {
                    qDebug() << "\tAppending a message...";
                    messages.append(cur);
                }
            }

            QStringList u = data.at(3).split("&&"); //read the user info from the data
            for (it = u.begin(); it < u.end(); it++)
            {
                QString cur = *it;
                if (cur != "")
                {
                    QStringList uData = cur.split(":");

                    User toadd;
                    toadd.username = uData.front();
                    QStringList p = uData.back().split(",");
                    QStringList::iterator i;
                    for (i = p.begin(); i < p.end(); i++)
                    {
                        QString c = *i;
                        toadd.permittedToSee.append(c);
                    }
                    usersList.append(toadd);
                }
            }
        }
    }
    else if (data.front() == "2")   //if this is true, it is only the server sending a new message to the client
    {
        qDebug() << "\tJust a tiny update message...";
        if (data.size() < 2)
        {
            qDebug() << "data.size() IS NOT LESS THAN TWO... RETURNING (2 message format)";
            return;
        }
        messages.append(data.back());
    }

    qDebug() << "\tFinished reading message from server and populating...";
    //end parsing message data

    //the following determines the GUI operations to take based on the number page currently being viewed
    if (this->ui->stackedWidget->currentIndex() == 0)   //for the login page
    {
        if (superadmin)
        {
            this->resize(1056, 327);
            this->ui->stackedWidget->resize(1051, 291);
            ui->stackedWidget->setCurrentIndex(2);
            Update_Management();
        }
        else
        {
            this->resize(802, 327);
            this->ui->stackedWidget->resize(801, 291);
            ui->stackedWidget->setCurrentIndex(1);
            Update_Client();
        }
    }
    else if (this->ui->stackedWidget->currentIndex() == 1)  //update the message list for the client page
    {
        Update_Client();
    }
    else if (this->ui->stackedWidget->currentIndex() == 2)  //update the message list and the user list for the super admin client page
    {
        Update_Management();
    }
    else if (this->ui->stackedWidget->currentIndex() == 3)  //update the permissions lists if the super admin is on the permission editing page
    {
        Update_Editor();
    }
    ui->Status->setText("");
    blockSize = 0;
}
void MainWindow::SSL_Error(QList<QSslError> errors)
{
    QList<QSslError>::iterator it;
    for (it = errors.begin(); it < errors.end(); it++)
    {
        QSslError cur = *it;
        qDebug() << "We got an SSL Error...";
        qDebug() << cur.errorString();
    }
}









//GUI SLOTS
void MainWindow::on_Welcome_SignIn_clicked()
{
    qDebug() << "Welcome Sign In clicked";

    if (ui->Welcome_Username->text() == "" || ui->Welcome_IP->text() == "" || ui->Welcome_Password->text() == "")     //verifies all fields are input correctly
    {
        QMessageBox::warning(this, tr("Invalid Sign In"), tr("Please ensure you have entered an IP address, port, username, and password."),
                                                         QMessageBox::Ok | QMessageBox::Default);
        return;
    }

    serverIP = ui->Welcome_IP->text();
    username = ui->Welcome_Username->text();
    password = ui->Welcome_Password->text();
    port = ui->Welcome_port->text().toInt();

    this->ui->Welcome_Username->setFocus();

    //serverIP = "127.000.000.001";
    port = 50000;
    //username = "Roger";
    //password = "clotz";


    secureSocket->setPeerVerifyMode(QSslSocket::QueryPeer);         //connect to server
    secureSocket->connectToHostEncrypted(serverIP, port);
    ui->Status->setText("Establishing connection with host...");
    if (!secureSocket->waitForEncrypted(1000)) {
        QMessageBox::warning(this, tr("Invalid Sign In"), tr("Could not connect to host."),
                                                         QMessageBox::Ok | QMessageBox::Default);
        ui->Status->setText("");
        return;
    }

    ui->Status->setText("Authenticating credentials...");
    QString msgToSend = username + "::" + password + "::usr::auth";     //message for authentication
    Send_Message(msgToSend);    //sending message to the server

    this->setEnabled(false);    //disable GUI until we receive a message back from the server. Handled in the Receive_Message() slot

    //this->ui->Welcome_IP->clear();
    this->ui->Welcome_Username->clear();
    this->ui->Welcome_Password->clear();
}

void MainWindow::on_Client_Send_clicked() //sending a message
{
    qDebug() << "Client Send clicked";

    if (this->ui->Client_MessageText->text() == "")
        return;

    QString tosend = this->ui->Client_MessageText->text();
    tosend.remove("::");
    tosend.remove("&&");
    tosend.remove("__");
    Send_Message(username+"::"+password+"::msg::new::"+tosend);   //send user input message

    this->ui->Client_MessageText->clear();
}
void MainWindow::on_Client_SignOut_clicked()
{
    qDebug() << "Client Sign Out clicked";

    secureSocket->disconnectFromHost();

    username = "";      //reset all private information
    password = "";
    serverIP = "";
    port = 0;

    messages.clear();
    usersList.clear();
    editing = "";
    superadmin = false;

    this->resize(649, 327);
    this->ui->stackedWidget->resize(651, 291);
    this->ui->stackedWidget->setCurrentIndex(0);    //go back to login screen
}

void MainWindow::on_Management_Send_clicked()//Super-admin sending a message
{
    qDebug() << "Management Send clicked";

    if (this->ui->Management_MessageText->text() == "")
        return;

    QString tosend = this->ui->Management_MessageText->text();
    tosend.remove("::");
    tosend.remove("&&");
    tosend.remove("__");
    Send_Message(username+"::"+password+"::msg::new::"+tosend);   //send user input message

    this->ui->Management_MessageText->clear();
}
void MainWindow::on_Management_SignOut_clicked()
{
    qDebug() << "Management Sign Out clicked";

    secureSocket->disconnectFromHost();

    username = "";  //reset all local private data
    password = "";
    serverIP = "";
    port = 0;

    messages.clear();
    usersList.clear();
    editing = "";
    superadmin = false;

    this->resize(649, 327);
    this->ui->stackedWidget->resize(651, 291);
    this->ui->stackedWidget->setCurrentIndex(0);    //go back to login screen
}
void MainWindow::on_Management_Add_clicked()//Super Admin attempting to add a new user
{
    qDebug() << "Management Add clicked";

    SmallWindow GetName(0, 0);  //new popup to get query information from the user
                                    //asks for username and password
    GetName.show();
    GetName.exec();

    QStringList newuser = GetName.returnInfo("0x1289"); //reads info from the SmallWindow class

    if (newuser.front() == "" || newuser.back() == "")
        return;

    Send_Message(username+"::"+password+"::usr::add::"+newuser.front()+"::"+newuser.back());    //sends message to server to add new user
}
void MainWindow::on_Management_Remove_clicked()//Super Admin attempting to remove an account
{
    qDebug() << "Management Remove clicked";

    QList<QListWidgetItem *> selected = this->ui->Management_Accounts->selectedItems(); //get all GUI selected items - can only be one item due to settings
    if (selected.empty())
        return;

    SmallWindow Confirmation(1, 0); //popup to verify username and password for this command.
    Confirmation.show();
    Confirmation.exec();

    QStringList userdata = Confirmation.returnInfo("0x1289");
    if (userdata.front() == username && userdata.back() == password)//verify login information
    {
        Send_Message(username+"::"+password+"::usr::del::"+selected.front()->text());//send remove user to server
    }
    else
    {
        QMessageBox::warning(this, tr("Invalid Sign In"), tr("Incorrect username and/or password."),
                                                         QMessageBox::Ok | QMessageBox::Default);
        on_Management_SignOut_clicked(); //automatically sign the user out if his information is invalid
        return;
    }
}
void MainWindow::on_Management_Edit_clicked()//edit user information
{
    qDebug() << "Management Edit clicked";

    QList<QListWidgetItem *> selected = this->ui->Management_Accounts->selectedItems(); //return which user is selected on the list
    if (selected.empty())
        return;

    this->ui->Permissions_username->setText("Permissions for User "+selected.front()->text());
    editing = selected.front()->text();
    Update_Editor();            //Update the permissions changing GUI

    this->resize(649, 327);
    this->ui->stackedWidget->resize(651, 291);
    this->ui->stackedWidget->setCurrentIndex(3); //Go to permissions page
}

void MainWindow::on_Permissions_DenyAll_clicked()   //remove all users from being seen by this user
{
    qDebug() << "Permissions Deny All clicked";

    QList<User>::iterator it;
    for (it = usersList.begin(); it < usersList.end(); it++)
    {
        User * cur = &*it;
        if (cur->username == editing)   //editing is the current user being edited. Stores as a QString
        {
            cur->permittedToSee.clear();//clear the entire list
        }
    }

    Update_Editor();
}
void MainWindow::on_Permissions_DenyOne_clicked()   //remove selected user from being seen
{
    qDebug() << "Permissions Deny One clicked";

    QList<QListWidgetItem *> selected = this->ui->Permissions_Permit->selectedItems();
    if (selected.empty())
        return;

    QList<User>::iterator it;
    for (it = usersList.begin(); it < usersList.end(); it++)
    {
        User * cur = &*it;
        if (cur->username == editing)   //editing is the current user being edited. Stores as a QString
        {
            QStringList::Iterator it;
            int i = 0;
            for (it = cur->permittedToSee.begin(); it < cur->permittedToSee.end(); it++)//iterates through the users until it finds the one it's looking for, then stores that index value in i
            {
                QString cur = *it;
                if (cur == selected.front()->text())
                    break;
                else
                    i++;
            }
            cur->permittedToSee.removeAt(i);    //remove the specific user from the list by index value i
        }
    }

    Update_Editor();    //update the view
}
void MainWindow::on_Permissions_PermitAll_clicked() //add all users to permitted list
{
    qDebug() << "Permissions Permit All clicked";

    QList<User>::iterator it;
    for (it = usersList.begin(); it < usersList.end(); it++)
    {
        User * cur = &*it;
        if (cur->username == editing)   //editing is the current user being edited. Stores as a QString
        {
            cur->permittedToSee.clear();//clear the list before adding every user

            QList<User>::iterator it2;
            for (it2 = usersList.begin(); it2 < usersList.end(); it2++)//add all users to the list
            {
                User c = *it2;
                cur->permittedToSee.append(c.username);
            }
        }
    }

    Update_Editor();
}
void MainWindow::on_Permissions_PermitOne_clicked()
{
    qDebug() << "Permissions Permit One clicked";

    QList<QListWidgetItem *> selected = this->ui->Permissions_Deny->selectedItems();
    if (selected.empty())
        return;
    QList<User>::iterator it;
    for (it = usersList.begin(); it < usersList.end(); it++)
    {
        User * cur = &*it;
        if (cur->username == editing)   //editing is the current user being edited. Stores as a QString
        {
            cur->permittedToSee.append(selected.front()->text());
        }
    }

    Update_Editor();
}
void MainWindow::on_Permissions_Save_clicked() //first verify user's identity, then send changes to the server
{
    qDebug() << "Permissions Save clicked";

    SmallWindow Confirmation(1, 0);//used to validate users information. Asks for username and password
    Confirmation.show();
    Confirmation.exec();

    QStringList userdata = Confirmation.returnInfo("0x1289");
    if (userdata.front() == username && userdata.back() == password)
    {
        QString msgToSend = username+"::"+password+"::acl::"+editing+":";

        //QList<QListWidgetItem *> items = this->ui->Permissions_Permit->items();
        while (this->ui->Permissions_Permit->count() != 0)
        {
            QListWidgetItem * cur = this->ui->Permissions_Permit->takeItem(0);
            if (cur->text() != "")
                msgToSend.append(cur->text()+",");
        }
        Send_Message(msgToSend);
    }
    else
    {
        QMessageBox::warning(this, tr("Invalid Sign In"), tr("Incorrect username and/or password."),
                                                         QMessageBox::Ok | QMessageBox::Default);
        on_Management_SignOut_clicked();    //automatically sign the user out if his information is invalid
        return;
    }

    this->resize(1056, 327);
    this->ui->stackedWidget->resize(1051, 291);
    this->ui->stackedWidget->setCurrentIndex(2);
    editing = "";   //reset the name of the person being edited
}











//private member functions
void MainWindow::Update_Client()    //function to update the page 1 of the GUI
{
    this->ui->Client_MessageDiplay->clear();

    QStringList::iterator it;
    for (it = messages.begin(); it < messages.end(); it++)//display all messages received from the server
    {
        QString cur = *it;
        QStringList data = cur.split("__");
        QString temp = data.at(1);
        temp.replace("T", " ");

        QTreeWidgetItem * toadd = new QTreeWidgetItem;
        toadd->setText(0, data.front());
        toadd->setText(1, temp);
        toadd->setText(2, data.back());

        this->ui->Client_MessageDiplay->addTopLevelItem(toadd);
    }
    this->ui->Client_MessageDiplay->sortItems(1, Qt::AscendingOrder);

    this->ui->Client_MessageDiplay->scrollToBottom();
}
void MainWindow::Update_Management()    //function to update the page 2 of the GUI
{
    this->ui->Management_MessageDisplay->clear();
    qDebug() << "Enter Update Management";
    QStringList::iterator it;
    for (it = messages.begin(); it < messages.end(); it++)  //display all messages received from the server
    {
        QString cur = *it;
        qDebug() << cur;
        QStringList data = cur.split("__");
        QString temp = data.at(1);
        temp.replace("T", " ");

        QTreeWidgetItem * toadd = new QTreeWidgetItem;
        toadd->setText(0, data.front());
        toadd->setText(1, temp);
        toadd->setText(2, data.back());

        this->ui->Management_MessageDisplay->addTopLevelItem(toadd);
    }
    qDebug() << "After display messages";
    this->ui->Management_MessageDisplay->sortItems(1, Qt::AscendingOrder);
    this->ui->Management_MessageDisplay->scrollToBottom();

    this->ui->Management_Accounts->clear();

    QList<User>::iterator it2;
    for (it2 = usersList.begin(); it2 < usersList.end(); it2++) //display all usernames received from the server
    {
        User cur = *it2;

        this->ui->Management_Accounts->addItem(cur.username);
    }
    this->ui->Management_Accounts->sortItems(Qt::AscendingOrder);
}
void MainWindow::Update_Editor()    //function to update the page 3 of the GUI
{
    this->ui->Permissions_Deny->clear();
    this->ui->Permissions_Permit->clear();

    QList<User>::iterator it2;
    for (it2 = usersList.begin(); it2 < usersList.end(); it2++)
    {
        User cur = *it2;

        if (cur.username == editing)    //if the username is the one we're editing
        {
            QStringList::iterator it;
            for (it = cur.permittedToSee.begin(); it < cur.permittedToSee.end(); it++)//populate the permitted to see GUI list
            {
                QString c = *it;
                if (c != "")
                    this->ui->Permissions_Permit->addItem(c);
            }
            QList<User>::iterator it3;
            for (it3 = usersList.begin(); it3 < usersList.end(); it3++)//populate the not permitted to see GUI list
            {
                User c = *it3;

                if (!cur.permittedToSee.contains(c.username))
                    this->ui->Permissions_Deny->addItem(c.username);
            }
        }
    }

    this->ui->Permissions_Deny->sortItems(Qt::AscendingOrder);
    this->ui->Permissions_Permit->sortItems(Qt::AscendingOrder);
}
void MainWindow::Send_Message(QString message)//send a message to the server
{
    qDebug() << "sending a message";
    qDebug() << message;
    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_0);
    out << (quint16)0;  //allocate space for the size variable
    out << message; //write the message
    out.device()->seek(0); //go back to front of black array
    out << (quint16)(block.size() - sizeof(quint16)); //put in the size in previously reserved space

    qDebug() << secureSocket->write(block);//send to server
}













//test population functions
bool MainWindow::Validate_Credentials()
{
    if (username == "Roger" && password == "clotz")
        return true;
    else
        return false;
}
void MainWindow::Populate_Client()
{
    messages.clear();
    superadmin = false;
    messages.append("steven::02/17/2012 02:55:32::I am a message from the future!");
    messages.append("salem::02/07/2012 02:57:14::It was number fourteen...");
    messages.append("salem::02/07/2012 02:58:01::Bagels that contain no holes!");
    messages.append("ralph::02/07/2012 08:15:54::Cryptic messages are cryptic");
    messages.append("steven::02/17/2011 02:55:32::I am a message from the distant past!");
    usersList.clear();
}
void MainWindow::Populate_Management()
{

}
